<?php
// +----------------------------------------------------------------------
// | INPHP
// | Copyright (c) 2023 https://inphp.cc All rights reserved.
// | Licensed ( https://opensource.org/licenses/MIT )
// | Author: 幺月儿(https://gitee.com/lulanyin) Email: inphp@qq.com
// +----------------------------------------------------------------------
// | redis 连接
// +----------------------------------------------------------------------
namespace Inphp\Core\Db\Redis;

use Inphp\Core\Db\ConnectionPool;
use Inphp\Core\Service;
use Redis;

class Connection
{
    /**
     * 配置
     * @var array
     */
    private array $config = [
        //服务器地址
        "host"      => "127.0.0.1",
        //端口
        "port"      => 6379,
        //密码
        "password"  => "",
        //选择库
        "select"    => 0,
        //超时
        "timeout"   => 3,
        //读超时时间
        "readTimeout" => 3,
        //缓存过期时间，-1为永不过期
        "expire"    => 86400,
        //重试间隔
        "retryInterval" => 0,
        //缓存名前缀
        "prefix"    => "redis_inphp_",
        //连接池数量
        "pools"     => 64
    ];

    /**
     * 原对象
     * @var Redis
     */
    public Redis $redis;

    /**
     * 连接池
     * @var ConnectionPool|null
     */
    public ConnectionPool|null $pool = null;

    /**
     * 初始化连接对象
     * @param array $config
     */
    public function __construct(array $config)
    {
        $this->config = $config;
        if (Service::isCLI()) {
            $poolLength = $config["pools"];
            $poolLength = is_numeric($poolLength) && $poolLength > 0 ? ceil($poolLength) : 64;
            //使用连接池
            $this->pool = new ConnectionPool(function () {
                $redis = new Redis();
                if ($this->connect($redis)) {
                    return $redis;
                }
                return null;
            }, $poolLength);
        } else {
            //使用普通对象即可
            $this->redis = new Redis();
            $this->connect($this->redis);
        }
    }

    /**
     * 连接
     * @param Redis $redis
     * @return bool
     */
    public function connect(Redis $redis): bool
    {
        $arguments = [
            $this->config["host"] ?? "127.0.0.1",
            $this->config["port"] ?? 6379,
        ];
        $this->config["timeout"] = is_numeric($this->config["timeout"]) && $this->config["timeout"] > 0 && $this->config["timeout"] <= 5 ? ceil($this->config["timeout"]) : 3;
        if ($this->config["timeout"] !== 0) {
            $arguments[] = $this->config["timeout"];
        }
        $this->config["retryInterval"] = is_numeric($this->config["retryInterval"]) && $this->config["retryInterval"] > 0 && $this->config["retryInterval"] <= 5 ? ceil($this->config["retryInterval"]) : 3;
        if ($this->config['retryInterval'] !== 0) {
            /* reserved should always be NULL */
            $arguments[] = null;
            $arguments[] = $this->config['retryInterval'];
        }
        $this->config["readTimeout"] = is_numeric($this->config["readTimeout"]) && $this->config["readTimeout"] > 0 && $this->config["readTimeout"] <= 5 ? ceil($this->config["readTimeout"]) : 0;
        if ($this->config['readTimeout'] !== 0) {
            $arguments[] = $this->config['readTimeout'];
        }
        $bool = $redis->connect(...$arguments);
        if ($this->config['password']) {
            $redis->auth($this->config['password']);
        }
        if ($this->config['select'] !== 0) {
            $redis->select($this->config['select']);
        }
        return $bool;
    }

    /**
     * 获取Redis操作对象
     * @return Redis
     */
    public function get(): Redis
    {
        return Service::isCLI() ? $this->pool->get() : $this->redis;
    }

    /**
     * 回收
     * @param Redis $redis
     */
    public function put(Redis $redis): void
    {
        $this->pool?->put($redis);
    }
}